# -*- coding: utf-8 -*-
# created on 2017/2/9
from mathsolver.functions.base import *
from sympy import *
from mathsolver.functions.mathematica.mathematicaSolve import MathematicaSolve


class Intersect(BaseFunction):
    def solver(self, *args):
        lie, cve, points = args
        objs = points.objs
        if not (str(cve.value[0]) == "y" and str(cve.value[1]) == "0"):
            ineqs = [[p1.value[1], "!=", p2.value[1]] for p1, p2 in zip(objs, objs[1:])]
        else:
            ineqs = [[p1.value[0], "!=", p2.value[0]] for p1, p2 in zip(objs, objs[1:])]

        eqs = []
        for pt in points.objs:
            xx, yy = pt.sympify()
            eqs.append([tmp.subs({Symbol("x"): xx, Symbol("y"): yy}) for tmp in lie.sympify()])
            eqs.append([tmp.subs({Symbol("x"): xx, Symbol("y"): yy}) for tmp in cve.sympify()])

        ineqs += eqs
        ineqs.extend(self.known["inequations"])
        ineqs = BaseIneqs(ineqs)
        self.steps.append(
            ["%s 直线%s与%s交于%s" % (latex_symbol["because"], lie.printing(), cve.printing(), points.printing()), ""])
        self.steps.append([ineqs.printing(), ""])
        if not isinstance(cve, BasePaoWuXian) and len(objs) <= 2 and all(
                [sym.is_Symbol for p in objs for sym in p.sympify()]):
            point_symbols = [sym for p in objs for sym in p.sympify()]
            ans = MathematicaSolve().solver(ineqs, BaseVariables(point_symbols)).output[0].value
            key, values = list(ans.items())[0]
            # if len(values) == len(points.objs):
            values = sorted(values, key=lambda tt: sum([isinstance(v, Set) for v in tt]))[-1]
            new_ans = dict([(k, v) for k, v in zip(key, values) if not isinstance(v, Set)])
            point_values = [new_ans[sym] if sym in new_ans else sym for sym in point_symbols]
            for k, v in new_ans.items():
                if k not in point_symbols:
                    self.output.append(BaseEq([k, v]))

            # assert len(set(point_values)) == len(points.objs)
            points.objs[0].value = point_values[:2]
            points.objs[1].value = point_values[2:]
            self.output.extend(points.objs)
            self.steps.append(["交点为%s" % points.printing(), ""])
            return self

        self.output.append(ineqs)
        self.label.add("求两图像的交点")
        return self


class LineIntersectShuangQu(BaseFunction):
    def solver(self, *args):
        zhixian, shuangqu, points = args
        p1, p2 = points.objs
        ineqs = [[p1.value[0], ">", "0"], [p2.value[0], "<", "0"]]
        eqs = []
        for pt in points.objs:
            xx, yy = pt.sympify()
            eqs.append([tmp.subs({Symbol("x"): xx, Symbol("y"): yy}) for tmp in zhixian.sympify()])
            eqs.append([tmp.subs({Symbol("x"): xx, Symbol("y"): yy}) for tmp in shuangqu.sympify()])

        ineqs = BaseIneqs(ineqs + eqs)
        syms = set([sym for sym in points.free_symbols()])
        ans = MathematicaSolve().solver(ineqs, BaseVariables(syms)).output[0].value
        syms = sorted([sym for sym in syms], key=lambda tt: str(tt)[::-1])
        ans = search_multiple(ans, syms)
        v = ans.pieces[0][0]
        self.output.append(BasePoint({"name": p1.name, "value": v[:2]}))
        self.output.append(BasePoint({"name": p2.name, "value": v[2:]}))
        self.label.add("求两图像的交点")
        return self


class LineIntersect(BaseFunction):
    def get_intersect(self, eq1, eq2):
        ineqs = [eq1.sympify()] + [eq2.sympify()]
        for eq in [eq1, eq2]:
            if isinstance(eq, BasePartial) and eq.cond:
                if isinstance(eq.cond, (BaseIneqs, BaseEq)):
                    ineqs.extend(eq.cond.sympify())
                else:
                    ineqs.append(eq.cond.sympify())

        ineqs.extend(self.known["inequations"])
        if isinstance(eq1, BaseZhiXian) and len(eq1.name) > 1 and "_" not in eq1.name:
            p1 = self.search(eq1.name[0]).sympify()
            p2 = self.search(eq1.name[1]).sympify()
            ineqs.append(["x", "!=", p1[0]])
            ineqs.append(["x", "!=", p2[0]])
            ineqs.append(["y", "!=", p1[1]])
            ineqs.append(["y", "!=", p2[1]])

        ineqs = BaseIneqs(ineqs)
        ans = MathematicaSolve().solver(ineqs, BaseVariables(["x", "y"])).output[0].value
        assert len(ans) == 1
        ans = search_multiple(ans, [Symbol("x"), Symbol("y")])
        points = []
        if isinstance(ans, FiniteSet):
            values = ans.args
        elif isinstance(ans, PieceWise):
            values = [v for v, _ in ans.pieces]

        assert len(set(values)) <= 2
        for value in set(values):
            if str(value[0]) != "x" and str(value[1]) != "y":
                points.append({"name": "", "value": value})

        if len(points) == 1:
            return BasePoint(points[0])
        elif len(points) > 1:
            return BasePoints(points)
        else:
            raise ValueError()

    def solver(self, *args):
        eq1, eq2 = args
        try:
            obj = self.get_intersect(eq1, eq2)
            self.output.append(obj)
            self.steps.append(["%s与%s的交点为%s" % (eq1.printing(), eq2.printing(), obj.printing()), ""])
        except Exception:
            pt, _ = BasePointName("").init(self.exist_symbols)
            xx, yy = pt.sympify()
            eqs = []
            for eq in [eq1, eq2]:
                eqs.append([tmp.subs({Symbol("x"): xx, Symbol("y"): yy}) for tmp in eq.sympify()])
            self.output.append(pt)
            self.output.append(BaseEqs(eqs))
        self.label.add("求两图像的交点")

        return self


class LineIntersectOnePoint(LineIntersect):
    def solver(self, *args):
        eq1, eq2, pt = args
        try:
            obj = self.get_intersect(eq1, eq2)
            assert isinstance(obj, BasePoint)
            eqs = []
            for xx, yy in zip(obj.sympify(), pt.sympify()):
                if (xx - yy).free_symbols:
                    eqs.append([xx, yy])

            if len(eqs) == 1:
                self.output.append(BaseEq(eqs[0]))
            elif len(eqs) > 1:
                self.output.append(BaseEqs(eqs))
            else:
                raise ValueError()
        except Exception:
            xx, yy = pt.sympify()
            eqs = []
            for eq in [eq1, eq2]:
                eqs.append([tmp.subs({Symbol("x"): xx, Symbol("y"): yy}) for tmp in eq.sympify()])
            self.output.append(pt)
            self.output.append(BaseEqs(eqs))
        self.label.add("求两图像的交点")
        return self


if __name__ == '__main__':
    pass
